package cn.iocoder.yudao.module.bpm.service.definition;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.*;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.common.BpmCommonHandleVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.common.BpmHandleStatisticsRespVO;
import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmCommonMapper;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
import cn.iocoder.yudao.module.bpm.utils.BpmUtils;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_COMPLETE_FAIL_NOT_EXISTS;


/**
 * 流程公共服务
 */
@Service
@Validated
public class BpmCommonServiceImpl implements BpmCommonService {

    @Resource
    private BpmProcessInstanceApi processInstanceApi;

    @Resource
    private TaskService taskService;

    @Resource
    private BpmTaskService bpmTaskService;

    @Resource
    private BpmProcessInstanceService processInstanceService;

//    @Resource
//    private BpmTaskExtMapper taskExtMapper;

//    @Resource
//    private BpmTaskAssignRuleMapper taskAssignRuleMapper;

    @Resource
    private HistoryService historyService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private ManagementService managementService;

    @Resource
    private ProcessEngine processEngine;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private BpmCommonMapper bpmCommonMapper;


    /**
     * 创建流程并提交
     *
     * @param busId
     * @param reason
     * @param key
     * @param variables
     * @return
     */
    @DSTransactional
    //@TenantIgnore
    public BpmCommonCreateRespDTO createInstanceAndCompleteTask(String busId, String reason, String key, Map<String, Object> variables) {
        //System.out.println("===================" + RootContext.getXID());
        BpmCommonCreateRespDTO dto = createProcessInstance(busId, key, variables);
        if (dto != null && StringUtils.isNotEmpty(dto.getProcessInstanceId())) {
            dto = completeTask(dto.getProcessInstanceId(), reason, variables);
        }
        return dto;
    }

    /**
     * 创建流程实例
     *
     * @param busId
     * @param key
     * @param variables
     * @return
     */
    @DSTransactional
    //@TenantIgnore
    public BpmCommonCreateRespDTO createProcessInstance(String busId, String key, Map<String, Object> variables) {
        if (StringUtils.isNotEmpty(busId) && StringUtils.isNotEmpty(key)) {
            String pid = processInstanceService.createProcessInstance(SecurityFrameworkUtils.getLoginUserId(),
                    new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(key)
                            .setVariables(variables).setBusinessKey(busId));
            //获取当前人员任务
            Task task = taskService.createTaskQuery().processInstanceId(pid).singleResult();
            //获取活动对应节点扩展参数
            Map<String, String> taskExtend = getTaskExtend(task);
            //拼装返回参数
            BpmCommonCreateRespDTO dto = new BpmCommonCreateRespDTO();
            dto.setProcessInstanceId(pid);
            if (taskExtend != null && taskExtend.get("index") != null) {
                dto.setResult(Integer.valueOf(taskExtend.get("index")));
            }
            return dto;
        }
        return null;
    }

    /**
     * 提交流程
     *
     * @param processInstanceId
     * @param reason
     * @param variables
     */
    @DSTransactional
    //@TenantIgnore
    public BpmCommonCreateRespDTO completeTask(String processInstanceId, String reason, Map<String, Object> variables) {
        if (StringUtils.isNotEmpty(processInstanceId)) {
            Task task = checkTask(taskService.createTaskQuery().
                    taskAssignee(SecurityFrameworkUtils.getLoginUserId() + "").
                    processInstanceId(processInstanceId).singleResult());

            // 完成任务，审批通过
            taskService.complete(task.getId(), variables);
            //判断是否通过
            Object type = variables.get("type");
//            BpmTaskExtDO bpmTaskExtDO = new BpmTaskExtDO().setTaskId(task.getId()).setReason(reason);
//
//            if ("0".equals(type)) {
//                bpmTaskExtDO.setResult(BpmProcessInstanceResultEnum.REJECT.getResult());
//            } else {
//                bpmTaskExtDO.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
//            }
//            // 更新任务拓展表为通过
//            taskExtMapper.updateByTaskId(bpmTaskExtDO);
            //返回流程数据
            BpmCommonCreateRespDTO dto = new BpmCommonCreateRespDTO();
            ProcessInstance instance = processInstanceService.getProcessInstance(processInstanceId);
            if (instance == null || instance.isEnded()) {
                HistoricProcessInstance historicProcessInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
                Map<String, String> taskExtend = getEndTaskExtend(task.getProcessDefinitionId(), historicProcessInstance.getEndActivityId());

                if (taskExtend != null && taskExtend.get("index") != null) {
                    dto.setResult(Integer.valueOf(taskExtend.get("index")));
                }
            } else {
                //获取当前人员任务
                task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
                //获取活动对应节点扩展参数
                Map<String, String> taskExtend = getTaskExtend(task);
                //Map<String, String> taskExtend = getEndTaskExtend(instance.getProcessDefinitionId()) ;
                if (taskExtend != null && taskExtend.get("index") != null) {
                    dto.setResult(Integer.valueOf(taskExtend.get("index")));
                }
            }
            dto.setProcessInstanceId(processInstanceId);
            return dto;
        }
        return null;
    }

    /**
     * 校验任务是否存在， 并且是否是分配给自己的任务
     */
    private Task checkTask(Task task) {
        if (task == null) {
            throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
        }
        if (!Objects.equals(SecurityFrameworkUtils.getLoginUserId(), NumberUtils.parseLong(task.getAssignee()))) {
            throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
        }
        return task;
    }

    /**
     * 获取任务
     *
     * @param id
     * @return
     */
    private Task getTask(String id) {
        return taskService.createTaskQuery().taskId(id).singleResult();
    }

    /**
     * 获取任务对应活动的扩展
     *
     * @param processDefinitionId
     * @return
     */
    private Map<String, String> getEndTaskExtend(String processDefinitionId) {
        //返回参数
        Map<String, String> extendMap = new HashMap<>();
        if (StringUtils.isNotEmpty(processDefinitionId)) {
            //获取流程节点
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            FlowElement flowNode = bpmnModel.getProcesses().get(0).getFlowElementMap().get("endActivity");
            //FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(activityId);
            //获取node下的所有扩展
            extendMap = BpmUtils.getTaskExtend(flowNode);
        }
        return extendMap;
    }

    /**
     * 获取任务对应活动的扩展
     *
     * @param processDefinitionId
     * @return
     */
    private Map<String, String> getEndTaskExtend(String processDefinitionId, String activityName) {
        //返回参数
        Map<String, String> extendMap = new HashMap<>();
        if (StringUtils.isNotEmpty(processDefinitionId)) {
            //获取流程节点
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            FlowElement flowNode = bpmnModel.getProcesses().get(0).getFlowElementMap().get(activityName);
            //FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(activityId);
            //获取node下的所有扩展
            extendMap = BpmUtils.getTaskExtend(flowNode);
        }
        return extendMap;
    }

    /**
     * 获取任务对应活动的扩展
     *
     * @param task
     * @return
     */
    private Map<String, String> getTaskExtend(Task task) {
        //返回参数
        Map<String, String> extendMap = new HashMap<>();
        if (task != null) {
            //获取执行实体，为了获取活动id
            ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery()
                    .executionId(task.getExecutionId()).singleResult();

            //获取流程节点
            BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
            FlowElement flowNode = bpmnModel.getFlowElement(ee.getActivityId());
            //获取node下的所有扩展
            extendMap = BpmUtils.getTaskExtend(flowNode);
        }
        return extendMap;
    }


    /**
     * 查询待办分页
     *
     * @return
     */
    @TenantIgnore
    public PageResult<BpmCommonHandleDTO> selectHandleFlowPage(BpmCommonHandlePageDTO pageDTO) {
        PageResult<BpmCommonHandleDTO> result = new PageResult<>();
        result.setList(bpmCommonMapper.selectHandleFlow(pageDTO));
        result.setTotal(bpmCommonMapper.selectHandleFlowCount(pageDTO));
        return result;
    }

    /**
     * 查询已办分页
     *
     * @return
     */
    @TenantIgnore
    public PageResult<BpmCommonHandleDTO> selectHandleDoneFlowPage(BpmCommonHandlePageDTO pageDTO) {
        PageResult<BpmCommonHandleDTO> result = new PageResult<>();
        result.setList(bpmCommonMapper.selectHandleDoneFlow(pageDTO));
        result.setTotal(bpmCommonMapper.selectHandleDoneFlowCount(pageDTO));
        return result;
    }

    /**
     * 查询待办
     *
     * @return
     */
    @TenantIgnore
    public List<BpmCommonHandleTotalDTO> selectHandleTotal(String userCode) {
        return bpmCommonMapper.selectHandleTotal(userCode);
    }

    /**
     * 查询已办
     *
     * @return
     */
    @TenantIgnore
    public List<BpmCommonHandleTotalDTO> selectHandleDoneTotal(String userCode) {
        return bpmCommonMapper.selectHandleDoneTotal(userCode);
    }

    /**
     * 查询待办统计数据
     * @Author 王铁
     * @Description TODO
     * @Date 2024/10/24 10:50
     * @Version 1.0
     */
    @Override
    @TenantIgnore
    public List<BpmHandleStatisticsRespVO> getHandleStatistics(BpmCommonHandleVO reqVO) {
        return bpmCommonMapper.selectHandleStatistics(reqVO) ;
    }

    @Override
    public InputStream resourceRead(String id, String resType) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
        String resourceName = "";
        if (resType.equals("image/png")) {
            resourceName = processDefinition.getDiagramResourceName();
        } else if (resType.equals("text/xml")) {
            resourceName = processDefinition.getResourceName();
        }
        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        return resourceAsStream;
    }
}


